<?php
header("content-type:text/html;charset=utf-8");
class mysqliObject{
    /**
     * @var string 存储操作信息
     */
    public $msg = "";
    /**
     * @var mysqli|null 用于保存数据库资源对象，默认为NULL（未连接）
     */
    public $conn = null;
    /**
     * 功能：收集类的操作信息
     * @param $msg  操作信息
     * @param false $flag true表示成功信息，false表示失败信息
     */
    public function getMsg($msg,$flag=false){
        //判断$flag来确定要返回成功信息还是失败信息
        $this->msg .=  $flag ? "√{$msg} | " : "×{$msg} | ";
    }
    /**
     * mysqliObject constructor.
     * 功能：链接数据库服务器，选择数据库，设置链接编码
     *  @param string  $server   服务器地址
     *  @param string  $username 数据库服务器的用户名
     *  @param string  $password 数据库服务器的密码
     *  @param string  $db       数据库名称
     *  @param int     $port     端口号
     *  @param string  $charset  数据库服务器编码
     */
    public function __construct($server,$username,$password,$db,$port=3306,$charset='utf8'){
        //1.链接数据库，并选择数据库
        $this->conn = new mysqli($server,$username,$password,$db,$port);
        if($this->conn->connect_errno == 0){
            //链接成功
            $this->getMsg("链接数据库服务器$username@param {$server}:{$port}成功！并选择数据库：\"{$db}\"",true);
        }else{
            //链接失败
            $errno = $this->conn->connect_errno;
            $error = iconv('gbk','utf-8',$this->conn->connect_error);
            $this->getMsg("链接数据库服务器$username@param {$server}:{$port}失败，失败原因[{$errno}]:{$error}");
            return false;
        }
        //2.设置链接编码
        $thisCharset = $this->conn->character_set_name();
        //判断当前的链接编码与用户设置的链接编码是否相等，如果相等则不做任何操作，如果不相等则设置链接编码
        if($thisCharset != $charset){
            //设置链接编码
            $res =  $this->conn->set_charset($charset);
            if($res){
                $this->getMsg("设置链接编码\"{$charset}\"成功!",true);
                return true;
            }else{
                $errno = $this->conn->errno;
                $error = iconv('gbk','utf-8',$this->conn->error);
                $this->getMsg("设置链接编码\"{$charset}\"失败，失败原因[{$errno}]:{$error}");
                return false;
            }
        }else{
            $this->getMsg("当前链接编码为：\"{$charset}\"",true);
            return true;
        }
    }
    /**
     * 功能：执行增、删、改操作
     * @param $sql string $sql   sql语句
     * @return false|int 成功返回影响行数int，失败返回false
     */
    public function execSql($sql){
        //去掉首位空白
        $sql = trim($sql);
        //判断当前的SQL是否值增删改操作
        if (preg_match('/^(update)|(delete)|(insert)/i',$sql)){
            //执行SQL语句
            $res = $this->conn->query($sql);
            //判断当前SQL语句是否执行成功
            if($res){
                $this->getMsg("执行\"{$sql}\"成功",true);
                return $this->conn->affected_rows;
            }else{
                //执行失败
                $errno = $this->conn->errno;
                $error = iconv('gbk','utf-8',$this->conn->error);
                $this->getMsg("执行\"{$sql}\"失败，失败原因[{$errno}]:{$error}");
                return false;
            }
        }else{
            $this->getMsg("执行\"{$sql}\"失败，失败原因：".__FUNCTION__."()方法只能执行增删改操作，请修改SQL语句后重试");
            return false;
        }

    }
    /**
     * 功能：执行单条数据查询操作
     * @param string $sql 查询单条数据的SQL语句
     * @param const $result_type 返回数组的类型:MYSQL_ASSOC 关联数组 ;MYSQL_NUM 索引数组 ;MYSQL_BOTH 关联、索引二者都有的数组
     * @return false|mixed 失败返回false，成功返回查询结果
     */
    public function getOneData($sql,$result_type=MYSQLI_ASSOC){
        //去掉首位空白
        $sql = trim($sql);
        //判断当前的sql语句是否是查询语句
        if(preg_match("/^(select)/i",$sql)){
            //执行SQL语句,mysqli_query()函数如果执行的是查询语句，成功返回结果集，失败返回false
            $res = $this->conn->query($sql);
            if($res !== false){
                //判读当前的结果集中是否只有一条数据，如果多条则不允许
                if($res->num_rows > 1){
                    $this->getMsg("执行\"{$sql}\"失败，失败原因：".__FUNCTION__."()方法只能查询一条记录，如想查询多条记录请使用getMoreData()");
                    return false;
                }else {
                    //整理数据
                    $arr = $res->fetch_array($result_type);
                    $this->getMsg("执行\"{$sql}\"执行成功", true);
                    //释放结果集
                    $res->free();
                    return $arr;
                }
            }else{
                //操作失败
                $errno = $this->conn->errno;
                $error = iconv("gbk","utf-8",$this->conn->error);
                $this->getMsg("执行\"{$sql}\"失败，失败原因：[{$errno}]:{$error}");
                return false;
            }
        }else{
            //SQL语句不合法
            $this->getMsg("执行\"{$sql}\"失败，失败原因：".__FUNCTION__."()方法只能执行查询语句，请修改SQL语句后在试");
            return false;
        }
    }
    /**
     * 功能：执行多条数据查询操作
     * @param string $sql SQL语句
     * @param const $result_type 返回数组的类型:MYSQL_ASSOC 关联数组 ;MYSQL_NUM 索引数组 ;MYSQL_BOTH 关联、索引二者都有的数组
     * @return false|mixed 失败返回false，成功返回查询结果
     */
    public function getMoreData($sql,$result_type=MYSQLI_ASSOC){
        //去掉首位空白
        $sql = trim($sql);
        //判断当前的sql语句是否是查询语句
        if(preg_match("/^(select)/i",$sql)){
            //执行SQL语句,mysqli_query()函数如果执行的是查询语句，成功返回结果集，失败返回false
            $res = $this->conn->query($sql);
            if($res !== false){
                //整理数据
                $arr = $res->fetch_all($result_type);
                $this->getMsg("执行\"{$sql}\"执行成功", true);
                //释放结果集
                $res->free();
                return $arr;
            }else{
                //操作失败
                $errno = $this->conn->errno;
                $error = iconv("gbk","utf-8",$this->conn->error);
                $this->getMsg("执行\"{$sql}\"失败，失败原因：[{$errno}]:{$error}");
                return false;
            }
        }else{
            //SQL语句不合法
            $this->getMsg("执行\"{$sql}\"失败，失败原因：".__FUNCTION__."()方法只能执行查询语句，请修改SQL语句后在试");
            return false;
        }
    }
    /**
     * 查询当前用户的账单总金额
     * @param $id int 当前用户的ID
     * @return float 返回当前用户的账单总金额
     */
    public function getTotalMoney($id){
        $income_sql = "select sum(amount) as income from account where user_id = {$id} and type = 'income'";
        $expense_sql = "select sum(amount) as expense from account where user_id = {$id} and type = 'expense'";
        $income_res = $this->getOneData($income_sql);
        $expense_res = $this->getOneData($expense_sql);
        return (float)$income_res['income'] - (float)$expense_res['expense'];
    }
    /**
     * 查询当前用户的日志
     * @param $id int 当前用户的ID
     * @return Aarray 返回当前用户的活动记录
     */
    public function getLog($id){
        $log_sql = "select * from log where user_id = {$id}";
        $res = $this->getMoreData($log_sql);
        foreach($res as $key=>$val){
            $res[$key]['log_times'] = date("Y-m-d H:i:s",$val['log_times']);
        }
        return $res;
    }
    /**
     * 添加日志
     * @param $id 当前用户的ID属性
     * @param $username 当前用户的用户名
     * @param $logtype 当前日志的分类
     * @param $description 当前日志的描述
     */
    public function insertLog($id,$username,$logtype,$description){
        $instert_sql = "insert into log value(null,'%s',%d,'%s','%s','%s',%d)";
        $sql = sprintf($instert_sql,$logtype,$id,$username,$_SERVER["SERVER_ADDR"],$description,time());
        $res = $this->execSql($sql);
    }
    /**
     * mysqli destruct
     * 功能：关闭数据库连接、释放内存
     */
    public function __destruct()
    {
        $this->conn->close();
        unset($this->msg);
    }
}